package com.wpam.scrabble.mobile;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.Serializable;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;

import com.wpam.scrabble.mobile.activities.GameSettingsActivity;
import com.wpam.scrabble.mobile.ui.GameBoard;
import com.wpam.scrabble.mobile.ui.SquareBitmap;

public class MoveInfo implements Serializable {
	
	private static final long serialVersionUID = 1L;

	private static final int DIR_BOTH = 0;
	private static final int DIR_HORIZONTAL = 1;
	private static final int DIR_VERTICAL = 2;
	private static final int DIR_NONE = 3;
	private static final int DIR_ERROR = 4;
	
	private ArrayList<MovePart> letters_;
	private int points_;
	private int direction_;
	
	public MoveInfo() {

		this.letters_ = new ArrayList<MovePart>();
		this.points_ = 0;
		this.direction_ = DIR_NONE;
	}
	
	public void insertLetter(MovePart letter) {
		
		this.letters_.add(letter);
		if (letters_.size() > 1) {
			if (letters_.get(0).getCol() == letter.getCol())
				direction_ = (direction_ == DIR_NONE ? DIR_VERTICAL : (direction_ == DIR_VERTICAL ? DIR_VERTICAL : DIR_ERROR));
			else if (letters_.get(0).getRow() == letter.getRow())
				direction_ = (direction_ == DIR_NONE ? DIR_HORIZONTAL : (direction_ == DIR_HORIZONTAL ? DIR_HORIZONTAL : DIR_ERROR));
		}
	}
	
	public void resetMove() {

		this.letters_.clear();
		this.points_ = 0;
		this.direction_ = DIR_NONE;
	}
	
	public ArrayList<MovePart> getLetters() {
		return this.letters_;
	}

	public int getPoints() {
		return points_;
	}

	public boolean validate() {

		// Warunek 1. Czy s� jakie� literki
		if (letters_.size() == 0)
			return false;

		// Warunek 2. Czy jest to pierwsza runda?
		if (GameLogic.getInstance().isFirstTurn()) {
			boolean usesCenter = false;
			for (MovePart movePart : letters_) {
				if (movePart.getCol() == movePart.getRow() && movePart.getRow() == 7) {
					usesCenter = true;
					GameLogic.getInstance().getGameBoard().getSquare(movePart.getRow(), movePart.getCol()).setAccepted();
					break;
				}
			}
			if (!usesCenter)
				return false;
		}
		
		// Warunek 3. Czy s� w jednej linii
		if (direction_ == DIR_ERROR)
			return false;
		
		// Warunek 4. Czy tworz� ci�g�e s�owo i dotykaj� zaakceptowanej ju� litery
		MovePart[] moveParts = (MovePart[]) letters_.toArray(new MovePart[letters_.size()]);
		
		boolean touchesAccepted = moveParts[0].touchesAccepted();
		for (int i = 1; i < moveParts.length; ++i) {
			if (moveParts[i].getCol() == moveParts[0].getCol() 
					&& moveParts[i].getRow() > moveParts[0].getRow() + i) {
				// czy jest przerwa mi�dzy literkami
				for (int delta = moveParts[i-1].getRow(); delta < moveParts[i].getRow(); ++delta) {
					if (!GameLogic.getInstance().getGameBoard().getSquare(delta, moveParts[0].getCol()).isLetterSet())
						return false;
				}
			} else if (moveParts[i].getRow() == moveParts[0].getRow() 
					&& moveParts[i].getCol() > moveParts[0].getCol() + i) {
				// czy jest przerwa mi�dzy literkami
				for (int delta = moveParts[i-1].getCol(); delta < moveParts[i].getCol(); ++delta) {
					if (!GameLogic.getInstance().getGameBoard().getSquare(moveParts[0].getRow(), delta).isLetterSet())
						return false;
				}
			}
			if (!touchesAccepted) 
				touchesAccepted = moveParts[i].touchesAccepted();
		}
		if (!touchesAccepted)
			return false;
		
		return checkAndCountWords();
	}
	
	public boolean checkAndCountWords() {
		
		int row = letters_.get(0).getRow();
		int col = letters_.get(0).getCol();
		
		GameBoard gameBoard = GameLogic.getInstance().getGameBoard();
		
		if (direction_ == DIR_NONE) {
			if ((row > 1 && gameBoard.getSquare(row - 1, col).isLetterSet()) || (row < 14 && gameBoard.getSquare(row + 1, col).isLetterSet()))
				direction_ = DIR_VERTICAL;
			if ((col > 1 && gameBoard.getSquare(row, col - 1).isLetterSet()) || (col < 14 && gameBoard.getSquare(row, col + 1).isLetterSet())) {
				if (direction_ == DIR_NONE)
					direction_ = DIR_HORIZONTAL;
				else
					direction_ = DIR_BOTH;
			}
		}
		if (direction_ == DIR_BOTH || direction_ == DIR_HORIZONTAL) {
			this.points_ =  checkHorizontal(row, col, true);
			return points_ > 0;
		}
		else {
			this.points_ = checkVertical(row, col, true);
			return points_ > 0;
		}
	}
	
	private int checkVertical(int row, int col, boolean checkHorizontal) {
		
		int totalPoints = 0;
		
		while (row > 1 && GameLogic.getInstance().getGameBoard().getSquare(row - 1, col).isLetterSet())
			--row;
		
		StringBuilder builder = new StringBuilder();
		SquareBitmap current = GameLogic.getInstance().getGameBoard().getSquare(row, col);
		int modifier = 1;
		int points = 0;
		while (current.isLetterSet()) {
			builder.append(current.getLetter());
			if (current.isAccepted() && !GameLogic.getInstance().isFirstTurn()) 
				points += current.getPoints();
			else {
				switch(current.getType()){
				case SquareBitmap.BLANK:
					break;
				case SquareBitmap.LETTERx2:
					points += current.getPoints() * 2;
					break;
				case SquareBitmap.LETTERx3:
					points += current.getPoints() * 3;
					break;
				case SquareBitmap.NORMAL:
					points += current.getPoints();
					break;
				case SquareBitmap.WORDx2:
					points += current.getPoints();
					modifier *= 2;
					break;
				case SquareBitmap.WORDx3:
					points += current.getPoints();
					modifier *= 3;
					break;
				default:
					break;
				}
			}
			// Sprawdzenie czy ta literka nie stworzy�a te� s�owa w poziomie
			if (checkHorizontal && !current.isAccepted() 
					&& ((col > 0 && GameLogic.getInstance().getGameBoard().getSquare(row, col-1).isLetterSet()) 
							|| (col < 15 && GameLogic.getInstance().getGameBoard().getSquare(row, col+1).isLetterSet()))) {
				int pts = checkHorizontal(row, col, false);
				if (pts == -1)
					return -1;
				totalPoints += pts;
			}
			++row;
			current = GameLogic.getInstance().getGameBoard().getSquare(row, col);
		}
		if (!checkWord(builder.toString()))
			return -1;
		totalPoints += points * modifier;
		return totalPoints;
	}

	private int checkHorizontal(int row, int col, boolean checkVertical) {
		
		int totalPoints = 0;
		
		while (col > 1 && GameLogic.getInstance().getGameBoard().getSquare(row, col - 1).isLetterSet())
			--col;
		
		GameBoard gameBoard = GameLogic.getInstance().getGameBoard();
		StringBuilder builder = new StringBuilder();
		SquareBitmap current = gameBoard.getSquare(row, col);
		int modifier = 1;
		int points = 0;
		while (current.isLetterSet()) {
			builder.append(current.getLetter());
			if (current.isAccepted() && !GameLogic.getInstance().isFirstTurn()) 
				points += current.getPoints();
			else {
				switch(current.getType()){
				case SquareBitmap.BLANK:
					break;
				case SquareBitmap.LETTERx2:
					points += current.getPoints() * 2;
					break;
				case SquareBitmap.LETTERx3:
					points += current.getPoints() * 3;
					break;
				case SquareBitmap.NORMAL:
					points += current.getPoints();
					break;
				case SquareBitmap.WORDx2:
					points += current.getPoints();
					modifier *= 2;
					break;
				case SquareBitmap.WORDx3:
					points += current.getPoints();
					modifier *= 3;
					break;
				default:
					break;
				}
			}
			// Sprawdzenie czy ta literka nie stworzy�a te� s�owa w pionie
			if (checkVertical && !current.isAccepted() 
					&& ((row > 0 && gameBoard.getSquare(row - 1, col).isLetterSet()) 
							|| (row < 15 && gameBoard.getSquare(row + 1, col).isLetterSet()))) {
				int pts = checkVertical(row, col, false);
				if (pts == -1)
					return -1;
				totalPoints += pts;
			}
			++col;
			current = gameBoard.getSquare(row, col);
		}
		if (!checkWord(builder.toString()))
			return -1;
		totalPoints += points * modifier;
		return totalPoints;
	}

	private boolean checkWord(String word) {
		
		if (GameResources.getInstance().getBooleanPreference(GameSettingsActivity.WORD_CHECK, false)) {
			HttpURLConnection urlConnection = null;
	        String response = null;
	        try {
	            URL url = new URL("http://www.sjp.pl/" + URLEncoder.encode(word, "UTF-8"));
	            urlConnection = (HttpURLConnection) url.openConnection();
	            byte[] buffer = new byte[4500];
	            InputStream in = new BufferedInputStream(urlConnection.getInputStream());
	            in.read(buffer);
	            response = new String(buffer, "UTF-8");
	        }
	        catch (Exception e) {
	        	e.printStackTrace();
	        }
	        finally {
	            if (urlConnection != null)
	                urlConnection.disconnect();
	        }
	        if (response == null || !response.contains("dopuszczalne w grach"))
				return false;
		}
		return true;
	}
	
}